package com.second.app.thread.线程基础.day06.volatile关键字;

import java.util.HashMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @Author GYZ
 * @Date 2023/11/23
 * <pre>
 *   停不下来的原因主要是main线程一直在处理while循环，导致程序不能继续执行后面的代码
 *
 *   案例2：
 *      虽然从控制台输出看出来，程序确实被停止了。但是如果代码运行在 -server 服务器模式中64bit的JVM上时
 *      会出现死循环。
 *      解决办法：就是使用volatile关键字，关键字volatile的作用就是强制从公共堆栈中取得变量的值，而不是从线程私有数据栈中
 *              取得变量的值。
 *      为什么在服务器模式中64bit的jvm上时，会出现死循环？
 *          因为 private boolean isContinuePrint = true 存在于公共堆栈及线程的私有堆栈中。
 *          在JVM被设置为-server模式时为了线程运行的效率，线程一直在私有堆栈中取的isRunning值是true.而代码
 *          thread.setRunning(false)虽然被执行，更新的却是公共堆栈中的isRunning变量值为false.所以一直就是si
 *          循环的状态。
 *
 *      volatile:1.增加了实例变量在多个线程之间的可见性。但是不支持原子性。
 *                 它只能用来修饰变量。是线程同步的轻量级实现。性能肯定比synchronized要好。
 *               2.多线程访问volatile不会发生堵塞。但是synchronized会出现阻塞。
 *               3.volatile保证数据的可见性，但不能保证原子性；synchronized可以保证原子性，也可以
 *                 间接保证可见性。因为它会将私有内存和公共内存中的数据做同步。
 *       再次重申下，volatile解决的是变量在多个线程之间的可见性。而synchronized关键字解决的是多个线程之间访问资源的同步性。
 *
 *       线程安全包含原子性和可见性2个方面，java的同步机制都是围绕这2个方面来确保线程安全的。
 *
 *     案例3：volatile不具备同步性，也就是不具备原子性。
 *           这里突然有个疑问？？为什么加上要加上static关键字，才想到static修饰的关键字是被类的所有对象共享的。
 *           所以100个线程对象共享count变量，但是最终运行结果值不是10000。
 *           所以如何解决》去看案例四
 *
 *     案例4：所以解决方案就是1.在addCount方法上加上synchronized ,add方法一定要加上static关键字
 *                               这样就保证synchronized和static锁的内容就是MyThread.class类了
 *                        2.同时如果在方法前面加上synchronized关键字，也就没有必要使用volatile关键字声明变量了。
 *           3.volatile本身不处理数据的原子性，而是强制对数据的读写及时影响到主内存的。
 *             提示线程每次从共享内存中读取变量，而不是从私有内存中读取，这样就保证同步数据的可见性。
 *
 *           4.对于volatile修饰的变量，Jvm虚拟机只是保证从主内存加载到线程工作内存的值都是最新的，例如线程1和线程2都在执行
 *           read和load操作，发现主内存中的count值都是5，那么都会加载这个最新的值。也就是说，volatile解决的是变量同步时的可见性的问题。
 *           但无法保证原子性，对于多个线程访问同一个实例变量，还是需要加锁同步。
 *
 *      案例5：除了在i++操作时，使用synchronized关键字实现同步外 还可以使用AtomicInteger
 * </pre>
 */
//案例5
class TargetTask implements Runnable {
    ConcurrentMap<Integer, AtomicInteger> jbbTimeOutCountMap;

    public TargetTask(ConcurrentMap<Integer, AtomicInteger> jbbTimeOutCountMap) {
        this.jbbTimeOutCountMap = jbbTimeOutCountMap;
    }

    @Override
    public void run() {
        for (int i = 0; i < 2000; i++) {
            AtomicInteger atomicInteger = jbbTimeOutCountMap.putIfAbsent(22, new AtomicInteger(0));
            if (atomicInteger != null) {
                atomicInteger.incrementAndGet();
            }
        }
    }
}

class TargetTaskDemo {
    public static void main(String[] args) {
        ConcurrentHashMap<Integer, AtomicInteger> jbbTimeOutCountMap = new ConcurrentHashMap<>();
        TargetTask targetTask = new TargetTask(jbbTimeOutCountMap);
        for (int i = 0; i < 10; i++) {
            Thread thread = new Thread(targetTask);
            thread.start();
        }
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println(jbbTimeOutCountMap.get(22));

    }
}

//案例4
class MyThread01 extends Thread {

    public static int count;

    private static void addCount() {
        for (int i = 0; i < 100; i++) {
            count++;
        }
        System.out.println("count=" + count);
    }

    @Override
    public void run() {
        addCount();
    }
}

//案例3
class MyThread extends Thread {

    public static int count;

    private static void addCount() {
        for (int i = 0; i < 100; i++) {
            count++;
        }
        System.out.println("count=" + count);
    }

    @Override
    public void run() {
        addCount();
    }
}

class Example3 {
    public static void main(String[] args) {
        MyThread[] myThreadArray = new MyThread[100];
        for (int i = 0; i < 100; i++) {
            myThreadArray[i] = new MyThread();
        }
        for (int i = 0; i < 100; i++) {
            myThreadArray[i].start();
        }
    }
}


//案例2
class PrintStringDemo implements Runnable {

    private boolean isContinuePrint = true;

    public boolean isContinuePrint() {
        return isContinuePrint;
    }

    public void setContinuePrint(boolean isContinuePrint) {
        this.isContinuePrint = isContinuePrint;
    }

    public void printStringMethod() {
        try {
            while (isContinuePrint) {
                System.out.println("run printStringMethod threadName=" + Thread.currentThread().getName());
                Thread.sleep(1000);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void run() {
        printStringMethod();
    }
}

class PrintStringDemoRun {
    public static void main(String[] args) {
        PrintStringDemo printStringDemo = new PrintStringDemo();
        Thread thread = new Thread(printStringDemo);
        thread.start();
        System.out.println("我要停止它！stopThread=" + Thread.currentThread().getName());
        printStringDemo.setContinuePrint(false);
    }
}


//案例1
public class PrintString {
    private boolean isContinuePrint = true;

    public boolean isContinuePrint() {
        return isContinuePrint;
    }

    public void setContinuePrint(boolean continuePrint) {
        isContinuePrint = continuePrint;
    }

    public void printStringMethod() {
        try {
            while (isContinuePrint) {
                System.out.println("run printStringMethod threadName" + Thread.currentThread().getName());
                Thread.sleep(1000);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

//案例1
class Run {
    public static void main(String[] args) {
        PrintString printString = new PrintString();
        printString.printStringMethod();
        System.out.println("我要停止它！ stopThread=" + Thread.currentThread().getName());
        printString.setContinuePrint(false);
    }
}
